Sie sind auf Seite 1von 8

1/27/2019 CODEXPERT: Expresii lambda in C++

a presupunem ca vrem sa scriem un program care sa genereze o secventa de numere aleatoare pe care sa le afiseze in consola, apoi dintre acestea sa selecteze acele
numere care sunt pare si sa afiseze aceasta secventa in consola. Un astfel de program ar putea arata asa:

#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
#include <iterator>
#include <ctime>

using namespace std;

int randomizer() {return rand()%100;}

struct isodd : unary_function<int,bool>


{
bool operator() (int x) const {return x%2==1;}
};

int main()
{
srand((unsigned long)time(NULL));

// genereaza 10 numere aleatoare


vector<int> v1, v2;
generate_n(back_inserter(v1), 10, randomizer);

// afiseaza numele generate


for(vector<int>::iterator it = v1.begin(); it != v1.end(); ++it)
{
cout << *it << " ";
};
cout << endl;

// elimina numerele impare si copiaza cele ramanse intr-un nou vector


remove_copy_if(v1.begin(), v1.end(), back_inserter(v2), isodd());

// afiseaza noua secventa


for(vector<int<::iterator it = v2.begin(); it != v2.end(); ++it)
{
cout << *it << " ";
};
http://www.codexpert.ro/articole.php?id=30 1/8
1/27/2019 CODEXPERT: Expresii lambda in C++

cout << endl;

return 0;
}

Un posibil rezultat al rularii acestui program este:

41 67 34 0 69 24 78 58 62 64
34 0 24 78 58 62 64

In Visual Studio 2010 putem rescrie aceasta secventa de cod astfel:

int main()
{
srand((unsigned long)time(NULL));

// genereaza 10 numere aleatoare


vector<int> v1, v2;
generate_n(back_inserter(v1), 10, [] {return rand()%100;});

// afiseaza numele generate


for_each(v1.begin(), v1.end(), [](int i) {cout << i << " ";});
cout << endl;

// elimina numerele impare si copiaza cele ramanse intr-un nou vector


remove_copy_if(v1.begin(), v1.end(), back_inserter(v2), [](int i) -> bool {return (i%2) == 1;});

// afiseaza noua secventa


for_each(v2.begin(), v2.end(), [](int i) {cout << i << " ";});
cout << endl;

return 0;
}

Dupa cum se vede, codul e mai scurt, nu mai avem nevoie de functia randomizer() si nici de functorul isodd, in schimb am introdus cateva constructii noi:

[] {return rand()%100;}

[](int i) {cout << i << " ";}


http://www.codexpert.ro/articole.php?id=30 2/8
1/27/2019 CODEXPERT: Expresii lambda in C++

[](int i) -> bool {return (i%2) == 1;}

Acestea se numesc lambda si sunt constructii similare celor introduse cu cativa ani in urma in .NET. In C++ o expresie lambda are cateva componente. Sa luam spre
exemplu ultima dintre acestea.

lambda-introducer: aceasta este partea introductiva, care spune compilatorului ca urmeaza o expresie lambda; aici se specifica si ce variabile si in ce mod
(valoare sau referinta) se copiaza din blocul in care expresia lambda este definita (vom vedea acest lucru mai jos).
lambda-parameter-declaration: specifica parametrii expresiei lambda.
lambda-return-type-clause: specifica tipul la care se evalueaza expresia lambda; aceasta parte este optionala, cel mai adesea compilatorul putand deduce
implicit care este tipul expresiei. Este necesara specificare explicita a tipului doar atunci cand tipul valorii returnate este ambiguu. Pentru exemplul anterior
specificarea tipului valori returnate (> bool) nu este necesara.
compound-statement: reprezinta corpul expresiei lambda.

Iata un exemplu in care compilatorul nu poate deduce tipul returnat, si acesta trebuie specificat explicit:

vector<int> v1;
transform(v1.begin(), v1.end(), v1.begin(), [](int n) {
if(n > 0)
return n * 2;
else
return 0;
});

In cazul codului de mai sus compilatorul va arunca doua erori:

1>lambdas.cpp(68): error C3499: a lambda that has been specified to have a void return type cannot return a value
1>lambdas.cpp(70): error C3499: a lambda that has been specified to have a void return type cannot return a value

http://www.codexpert.ro/articole.php?id=30 3/8
1/27/2019 CODEXPERT: Expresii lambda in C++

Exista doua tipuri de expresii lambda: cu si fara stare. Cele pe care le-am vazut in exemplele de mai sus sunt fara stare. Ele nu contin variabile membru. Astfel de
lambda sunt introduse cu []. Se pot insa captura variabile din scopul in care este declarata expresia lambda, atat prin valoare cat si prin referinta. In acest caz vorbim de
lambda cu stare. Pentru a vedea modurile in care se pot capta variabile sa plecam de la exemplul urmator.

void function()
{
int a;
int b;
int c;

auto l = [] (int n) {};


}

Exemplele de mai jos arata posibilitatile de capturare a variabilelor a, b si c.

[] (int n) {}: nu se captureaza nimic.


[=] (int n) {}: se captureaza a, b, si c prin copiere.
[a] (int n) {}: se captureaza a prin copiere.
[&] (int n) {}: se captureaza a, b, si c prin referinta.
[&a] (int n) {}: se captureaza a prin referinta.
[a, &b, c] (int n) {}: se captureaza a si c prin valoare si b prin referinta.
[=, &b] (int n) {}: se captureaza a si c prin valoare si b prin referinta.
[&a, b, &c] (int n) {}: se captureaza a si c prin referinta si b prin valoare.
[&, b] (int n) {}: se captureaza a si c prin referinta si b prin valoare.

Dupa cum se observa se pot captura variabile prin copiere si valoare in orice combinatie posibila. Un caz special il reprezinta captarea pointerului this, care se face
intotdeauza prin valoare. Nu se poate specifica &this.
In exemplul de mai jos avem definita o clasa Range (cu un minim si maxim) care contine o functie ce filtreaza acele elemente ale unui vector care nu sunt intre limite,
returnand un vector nou doar cu elementele din raza de valori.

#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
#include <iterator>
#include <ctime>

using namespace std;


http://www.codexpert.ro/articole.php?id=30 4/8
1/27/2019 CODEXPERT: Expresii lambda in C++

template <typename T>


class Range
{
T m_min;
T m_max;
public:
Range(T a, T b): m_min(a), m_max(b){}

vector<T> Filter(const vector<T>& input)


{
vector<T> output;
remove_copy_if(
input.begin(), input.end(),
back_inserter(output),
[this](T n) {return !(this->m_min <= n && n <= this->m_max);});

return output;
}
};

int main()
{
srand((unsigned long)time(NULL));

// genereaza o secventa de 10 numere aleatoare


vector<int> v1;
generate_n(back_inserter(v1), 10, [] {return rand()%100;});

// afiseaza numele generate


for_each(v1.begin(), v1.end(), [](int i) {cout << i << " ";});
cout << endl;

Range<int> r(1, 25);

// filtreaza numerele din intervalul definit


vector<int> v2 = r.Filter(v1);

// afiseaza noua secventa


for_each(v2.begin(), v2.end(), [](int i) {cout << i << " ";});
cout << endl;

http://www.codexpert.ro/articole.php?id=30 5/8
1/27/2019 CODEXPERT: Expresii lambda in C++

return 0;
}

Un posibil rezultat pentru programul de mai sus este:

45 41 24 7 10 12 98 33 7 14
24 7 10 12 7 14

Sintaxa this->m_min este optionala, se poate scrie direct m_min.


In exemplul de mai sus folosim de 2 ori aceiasi functie lambda pentru afisarea elementelor unui vector. Pentru a evita acest lucru se poate folosi o variabila care sa ia
valoarea expresiei lambda si pasa functiei for_each. Pentru tipul acestei variabile se poate folosi cuvantul cheie auto, care in C++0x a primit o noua intrebuintare.

auto print = [](int i) {cout << i << " ";};

// afiseaza numele generate


for_each(v1.begin(), v1.end(), print);
cout << endl;

Urmatorul exemplu arata o functie lambda folosita pentru a calcula suma numerelor dintr-o secventa.

int main()
{
srand((unsigned long)time(NULL));

// genereaza o secventa de 10 numere aleatoare


vector<int> v1;
generate_n(back_inserter(v1), 10, [] {return rand()%100;});

// afiseaza numele generate


for_each(v1.begin(), v1.end(), [](int i) {cout << i << " ";});
cout << endl;

// calculeaza suma
int sum = 0;
for_each(v1.begin(), v1.end(), [&sum] (int n) {sum += n;});

// afiseaza suma
cout << "sum = " << sum << endl;

http://www.codexpert.ro/articole.php?id=30 6/8
1/27/2019 CODEXPERT: Expresii lambda in C++

return 0;
}

57 96 17 43 2 79 24 44 14 93
sum = 469

Variabila sum este capturata prin referinta, astfel incat valoare ei poate fi modificata. Expresia lambda din acest exemplu este transformata de compilator intr-un
functor.

class lambda_functor
{
int& m_sum;

public:
lambda_functor(int& sum) : m_sum(sum) {}

void operator() (int n)


{
m_sum += n;
}
};

Astfel, acest cod

int sum = 0;
for_each(v1.begin(), v1.end(), [&sum] (int n) {sum += n;});

devine

int sum = 0;
for_each(v1.begin(), v1.end(), lambda_functor(sum));

Datorita faptului ca functiile lambda sunt transformate de compilator in functori (function objects) acestea pot fi stocate in std::tr1::function. Iata un exemplu:

#include <iostream>
#include <vector>
#include <functional>
http://www.codexpert.ro/articole.php?id=30 7/8
1/27/2019 CODEXPERT: Expresii lambda in C++

#include <algorithm>
#include <iterator>
#include <string>

using namespace std;

template <typename T>


void apply(const vector<T>& data, const tr1::function<void (T)>& func)
{
for_each(data.begin(), data.end(), func);
}

int main()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);

apply<int>(v1, [](int n) {cout << n * n << " ";});


cout << endl;

vector<string> v2;
v2.push_back("marius");
v2.push_back("bancila");
v2.push_back("codexpert");

apply<string>(v2, [](string s) {cout << s << " ";});


cout << endl;

return 0;
}

Pentru alte informatii despre functiile lambda vedeti blogul echipei VC++. Informatii despre calculul lambda in matematica si programare se pot gasi
pe wikipedia. [phpBB Debug] PHP Warning: in file [ROOT]/phpbb/db/driver/mysqli.php on line 317: mysqli_free_result(): Couldn't fetch mysqli_result

http://www.codexpert.ro/articole.php?id=30 8/8

Das könnte Ihnen auch gefallen