Expressions Lambda en C ++

Lambda Expressions C



Per què Lambda Expression?

Penseu en la següent afirmació:

intmyInt= 52;

Aquí, myInt és un identificador, un valor. 52 és un literal, un valor. Avui en dia, és possible codificar una funció especialment i posar-la en la posició de 52. Aquesta funció s’anomena expressió lambda. Penseu també en el programa breu següent:







#incloure

utilitzant espai de nomshores;

intfn(inta través)

{

intcontesta=a través+ 3;

tornarcontesta;

}


intprincipal()

{

fn(5);



tornar 0;

}

Avui en dia, és possible codificar una funció especialment i posar-la en la posició de l’argument de 5, de la funció anomenada, fn (5). Aquesta funció s’anomena expressió lambda. L'expressió lambda (funció) en aquesta posició és un valor.



Qualsevol literal excepte la cadena literal és un valor prival. L’expressió lambda és un disseny de funcions especials que cabria com a literal al codi. És una funció anònima (sense nom). Aquest article explica la nova expressió principal de C ++, anomenada expressió lambda. El coneixement bàsic en C ++ és un requisit per entendre aquest article.



Contingut de l'article

Il·lustració de Lambda Expression

Al programa següent, una funció, que és una expressió lambda, s’assigna a una variable:





#incloure

utilitzant espai de nomshores;

automàticfn= [](intAtura)

{

intcontesta=Atura+ 3;

tornarcontesta;

};


intprincipal()

{

automàticvariab=fn(2);

cost <<variab<< ' n';


tornar 0;

}

La sortida és:

5

Fora de la funció main (), hi ha la variable, fn. El seu tipus és automàtic. Auto en aquesta situació significa que el tipus real, com ara int o float, està determinat per l'operant dret de l'operador d'assignació (=). A la dreta de l'operador d'assignació hi ha una expressió lambda. Una expressió lambda és una funció sense el tipus de retorn anterior. Tingueu en compte l’ús i la posició dels claudàtors, []. La funció retorna 5, un int, que determinarà el tipus de fn.



A la funció main () hi ha la sentència:

automàticvariab=fn(2);

Això significa que, fn fora de main (), acaba com l'identificador d'una funció. Els seus paràmetres implícits són els de l’expressió lambda. El tipus de variab és automàtic.

Tingueu en compte que l’expressió lambda acaba amb un punt i coma, igual que la definició de classe o estructura, acaba amb un punt i coma.

Al programa següent, una funció, que és una expressió lambda que retorna el valor de 5, és un argument per a una altra funció:

#incloure

utilitzant espai de nomshores;

buitotherfn(intno1,int (*ptr)(int))

{

intno2= (*ptr)(2);

cost <<no1<< '' <<no2<< ' n';

}


intprincipal()

{

otherfn(4,[](intAtura)

{

intcontesta=Atura+ 3;

tornarcontesta;

});


tornar 0;
}

La sortida és:

maig 4

Aquí hi ha dues funcions, l’expressió lambda i la funció otherfn (). L’expressió lambda és el segon argument de l’altrefn (), anomenat en main (). Tingueu en compte que la funció lambda (expressió) no acaba amb un punt i coma en aquesta trucada perquè, aquí, és un argument (no una funció autònoma).

El paràmetre de la funció lambda de la definició de la funció otherfn () és un punter cap a una funció. El punter té el nom, ptr. El nom, ptr, s'utilitza a la definició otherfn () per anomenar la funció lambda.

La declaració,

intno2= (*ptr)(2);

A la definició otherfn (), crida a la funció lambda amb un argument de 2. El valor de retorn de la trucada, '(* ptr) (2)' de la funció lambda, s'assigna a no2.

El programa anterior també mostra com es pot utilitzar la funció lambda en l’esquema de funció de devolució de trucada C ++.

Parts de Lambda Expression

Les parts d'una funció lambda típica són les següents:

[] () {}
  • [] és la clàusula de captura. Pot tenir elements.
  • () és per a la llista de paràmetres.
  • {} és per al cos de la funció. Si la funció està sola, hauria d'acabar amb un punt i coma.

Captures

La definició de la funció lambda es pot assignar a una variable o utilitzar-la com a argument d'una trucada de funció diferent. La definició d'aquesta crida de funció hauria de tenir com a paràmetre un punter cap a una funció, corresponent a la definició de la funció lambda.

La definició de la funció lambda és diferent de la definició de funció normal. Es pot assignar a una variable de l'abast global; aquesta funció assignada a variable també es pot codificar dins d'una altra funció. Quan s’assigna a una variable d’abast global, el seu cos pot veure altres variables a l’abast global. Quan s’assigna a una variable dins d’una definició de funció normal, el seu cos només pot veure altres variables a l’abast de la funció amb l’ajuda de la clàusula de captura, [].

La clàusula de captura [], també coneguda com a introductor lambda, permet enviar variables des de l’àmbit circumdant (funció) al cos de la funció de l’expressió lambda. Es diu que el cos de la funció de l’expressió lambda captura la variable quan rep l’objecte. Sense la clàusula de captura [], no es pot enviar una variable des de l’àmbit circumdant al cos de la funció de l’expressió lambda. El programa següent il·lustra això, amb l’abast de la funció main (), com l’àmbit circumdant:

#incloure

utilitzant espai de nomshores;

intprincipal()

{

intidentificador= 5;


automàticfn= [identificador]()

{

cost <<identificador<< ' n';

};

fn();


tornar 0;

}

La sortida és 5 . Sense el nom, id, dins [], l’expressió lambda no hauria vist la variable id de l’abast de la funció main ().

Captura per referència

L'exemple anterior d'ús de la clàusula de captura és la captura per valor (vegeu els detalls més avall). En la captura per referència, la ubicació (emmagatzematge) de la variable, per exemple, l’identificador anterior, de l’àmbit circumdant, es posa disponible dins del cos de la funció lambda. Per tant, canviar el valor de la variable dins del cos de la funció lambda canviarà el valor d’aquesta mateixa variable a l’àmbit circumdant. Cada variable que es repeteix a la clàusula de captura està precedida per la marca i (&) per aconseguir-ho. El programa següent ho il·lustra:

#incloure

utilitzant espai de nomshores;

intprincipal()

{

intidentificador= 5; flotarpeus= 2.3; charcap= 'A';

automàticfn= [&identificador,&peus,&cap]()

{

identificador= 6;peus= 3.4;cap= 'B';

};

fn();

cost <<identificador<< ',' <<peus<< ',' <<cap<< ' n';

tornar 0;

}

La sortida és:

6, 3.4, B

Confirmeu que els noms de variables dins del cos de la funció de l’expressió lambda corresponen a les mateixes variables fora de l’expressió lambda.

Captura per valor

En capturar per valor, es proporciona una còpia de la ubicació de la variable, de l’àmbit circumdant, dins del cos de la funció lambda. Tot i que la variable dins del cos de la funció lambda és una còpia, el seu valor no es pot canviar dins del cos a partir d’ara. Per aconseguir la captura per valor, cada variable repetida a la clàusula de captura no va precedida de res. El programa següent ho il·lustra:

#incloure

utilitzant espai de nomshores;

intprincipal()

{

intidentificador= 5; flotarpeus= 2.3; charcap= 'A';

automàticfn= [id, ft, cap]()

{

// id = 6; peus = 3,4; ch = 'B';

cost <<identificador<< ',' <<peus<< ',' <<cap<< ' n';

};

fn();

identificador= 6;peus= 3.4;cap= 'B';

cost <<identificador<< ',' <<peus<< ',' <<cap<< ' n';

tornar 0;

}

La sortida és:

5, 2.3, A

6, 3.4, B

Si s’elimina l’indicador de comentaris, el programa no es compilarà. El compilador emetrà un missatge d’error que indica que les variables de la definició de l’expressió lambda del cos de la funció no es poden canviar. Tot i que les variables no es poden canviar dins de la funció lambda, es poden canviar fora de la funció lambda, tal com mostra la sortida del programa anterior.

Barrejant captures

La captura per referència i la captura per valor es poden barrejar, tal com mostra el programa següent:

#incloure

utilitzant espai de nomshores;

intprincipal()

{

intidentificador= 5; flotarpeus= 2.3; charcap= 'A'; boolbl= cert;


automàticfn= [id, ft,&ch,&bl]()

{

cap= 'B';bl= fals;

cost <<identificador<< ',' <<peus<< ',' <<cap<< ',' <<bl<< ' n';

};

fn();


tornar 0;

}

La sortida és:

5, 2.3, B, 0

Quan tots són capturats, es fan per referència:

Si totes les variables que s'han de capturar es capturen per referència, només n'hi haurà prou amb una & a la clàusula de captura. El programa següent ho il·lustra:

#incloure

utilitzant espai de nomshores;

intprincipal()

{

intidentificador= 5; flotarpeus= 2.3; charcap= 'A'; boolbl= cert;


automàticfn= [&]()

{

identificador= 6;peus= 3.4;cap= 'B';bl= fals;

};

fn();

cost <<identificador<< ',' <<peus<< ',' <<cap<< ',' <<bl<< ' n';


tornar 0;

}

La sortida és:

6, 3.4, B, 0

Si algunes variables s’han de capturar per referència i d’altres per valor, llavors una & representarà totes les referències, i la resta no anirà precedida de res, com mostra el programa següent:

utilitzant espai de nomshores;

intprincipal()

{

intidentificador= 5; flotarpeus= 2.3; charcap= 'A'; boolbl= cert;


automàticfn= [&, id, ft]()

{

cap= 'B';bl= fals;

cost <<identificador<< ',' <<peus<< ',' <<cap<< ',' <<bl<< ' n';

};

fn();


tornar 0;

}

La sortida és:

5, 2.3, B, 0

Tingueu en compte que & alone (és a dir, & no seguit d'un identificador) ha de ser el primer caràcter de la clàusula de captura.

Quan tots són capturats, són per valor:

Si totes les variables que s'han de capturar han de ser capturades pel valor, només n'hi haurà prou amb una = a la clàusula de captura. El programa següent ho il·lustra:

#incloure

utilitzant espai de nomshores;

intprincipal()
{

intidentificador= 5; flotarpeus= 2.3; charcap= 'A'; boolbl= cert;


automàticfn= [=]()

{

cost <<identificador<< ',' <<peus<< ',' <<cap<< ',' <<bl<< ' n';

};

fn();


tornar 0;


}

La sortida és:

5, 2.3, A, 1

Nota : = és només de lectura, a partir d’ara.

Si algunes variables s’han de capturar per valor i d’altres per referència, aleshores one = representarà totes les variables copiades només de lectura, i la resta tindrà &, com mostra el programa següent:

#incloure

utilitzant espai de nomshores;

intprincipal()

{

intidentificador= 5; flotarpeus= 2.3; charcap= 'A'; boolbl= cert;


automàticfn= [=,&ch,&bl]()

{

cap= 'B';bl= fals;

cost <<identificador<< ',' <<peus<< ',' <<cap<< ',' <<bl<< ' n';

};

fn();


tornar 0;

}

La sortida és:

5, 2.3, B, 0

Tingueu en compte que = només ha de ser el primer caràcter de la clàusula de captura.

Esquema de funció de devolució de trucada clàssica amb expressió Lambda

El programa següent mostra com es pot fer un esquema de funció de devolució de trucada clàssic amb l'expressió lambda:

#incloure

utilitzant espai de nomshores;

char *sortida;


automàticcba= [](charfora[])

{

sortida=fora;

};



buitprincipalFunc(charentrada[],buit (*per)(char[]))

{

(*per)(entrada);

cost<<'per a la funció principal'<<' n';

}


buitfn()

{

cost<<'Ara'<<' n';

}


intprincipal()

{

charentrada[] = 'per a la funció de devolució de trucada';

principalFunc(entrada, cba);

fn();

cost<<sortida<<' n';



tornar 0;

}

La sortida és:

per a la funció principal

Ara

per a la funció de devolució de trucada

Recordeu que quan s’assigna una definició d’expressió lambda a una variable de l’abast global, el cos de la seva funció pot veure variables globals sense emprar la clàusula de captura.

El tipus final-retorn

El tipus de retorn d'una expressió lambda és automàtic, és a dir, el compilador determina el tipus de retorn a partir de l'expressió de retorn (si està present). Si realment el programador vol indicar el tipus de retorn, ho farà com al programa següent:

#incloure

utilitzant espai de nomshores;

automàticfn= [](intAtura) -> int

{

intcontesta=Atura+ 3;

tornarcontesta;

};


intprincipal()

{

automàticvariab=fn(2);

cost <<variab<< ' n';


tornar 0;

}

La sortida és 5. Després de la llista de paràmetres, s'escriu l'operador de fletxa. A continuació, segueix el tipus de retorn (int en aquest cas).

Tancament

Penseu en el segment de codi següent:

estructCla

{

intidentificador= 5;

charcap= 'A';

}obj1, obj2;

Aquí, Cla és el nom de la classe struct. Obj1 i obj2 són dos objectes que s’instanciaran a partir de la classe struct. L’expressió de Lambda és similar en la implementació. La definició de la funció lambda és una classe. Quan s'anomena (invoca) la funció lambda, s'instancia un objecte a partir de la seva definició. Aquest objecte s’anomena tancament. És el tancament el que fa la feina que s’espera que faci la lambda.

Tot i això, si codifiqueu l’expressió lambda com l’estructura anterior es substituiran obj1 i obj2 pels arguments dels paràmetres corresponents. El programa següent ho il·lustra:

#incloure

utilitzant espai de nomshores;

automàticfn= [](intparam1,intparam2)

{

intcontesta=param1+param2;

tornarcontesta;

} (2,3);


intprincipal()

{

automàticon=fn;

cost <<on<< ' n';


tornar 0;

}

La sortida és 5. Els arguments són 2 i 3 entre parèntesis. Tingueu en compte que la crida a la funció d’expressió lambda, fn, no accepta cap argument, ja que els arguments ja s’han codificat al final de la definició de la funció lambda.

Conclusió

L’expressió lambda és una funció anònima. Es divideix en dues parts: classe i objecte. La seva definició és una mena de classe. Quan es crida l'expressió, es forma un objecte a partir de la definició. Aquest objecte s’anomena tancament. És el tancament el que fa la feina que s’espera que faci la lambda.

Perquè l’expressió lambda rebi una variable d’un àmbit de funció exterior, necessita una clàusula de captura no buida al cos de la seva funció.