© Harry Broeders.
Deze pagina is bestemd voor studenten van de Haagse Hogeschool - Academie voor Technology, Innovation & Society Delft groep ECV.
De C++ standaard
staat op het punt om vernieuwd te worden. Zie:
http://en.wikipedia.org/wiki/C%2B%2B0x
. In deze nieuwe versie van
de standaard zijn lambda expressies en closures opgenomen, zie:
Lambda_Expressions_and_Closures.pdf
De voorbeelden zijn getest met Microsoft Visual C++ 2010 Express Edition. Deze versie van Visual C++ bied support voor lambda functies, zie: http://msdn.microsoft.com/en-us/library/dd293608.aspx
find_if
.
#include <iostream>
#include <list>
#include <algorithm>
#include <functional>
using namespace std;
bool ispos(int i) {
return i>=0;
}
class IsPos {
public:
bool operator()(int i) const {
return i>=0;
}
};
int main() {
list<int> l;
l.push_back(-3);
l.push_back(-4);
l.push_back(3);
l.push_back(4);
// Zoeken met behulp van een functie als zoekvoorwaarde.
auto r=find_if(l.begin(), l.end(), ispos);
if (r!=l.end())
cout<<"Het eerste positieve element is: "<<*r<<endl;
// Zoeken met behulp van een functie-object als zoekvoorwaarde.
r=find_if(l.begin(), l.end(), IsPos());
if (r!=l.end())
cout<<"Het eerste positieve element is: "<<*r<<endl;
// Zoeken met behulp van een standaard functie-object als zoekvoorwaarde.
r=find_if(l.begin(), l.end(), bind2nd(greater_equal<int>(),0));
if (r!=l.end())
cout<<"Het eerste positieve element is: "<<*r<<endl;
// Zoeken met behulp van een lambda functie-object als zoekvoorwaarde.
![]()
r=find_if(l.begin(), l.end(), [](int i) {
return i>=0;
});
if (r!=l.end())
cout<<"Het eerste positieve element is: "<<*r<<endl;
cin.get();
return 0;
}
for_each
.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
int main() {
vector<int> v;
v.push_back(-3);
v.push_back(-4);
v.push_back(3);
v.push_back(4);
ostream_iterator<int> iout(cout, " ");
copy(v.begin(), v.end(), iout);
cout<<endl;
for_each(v.begin(), v.end(), [](int i) {
![]()
cout<<i<<" "<<i<<" ";
});
cout<<endl;
cin.get();
return 0;
}
transform
.
#include <iostream>
#include <vector>
#include <iterator>
#include <functional>
#include <algorithm>
using namespace std;
int telop(int i, int j) {
return i+j;
}
int main() {
vector<int> v;
v.push_back(-3);
v.push_back(-4);
v.push_back(3);
v.push_back(4);
vector<int> w;
w.push_back(1);
w.push_back(2);
w.push_back(3);
w.push_back(4);
ostream_iterator<int> iout(cout, " ");
copy(v.begin(), v.end(), iout);
cout<<endl;
// Bewerking opgeven met een functie.
transform(v.begin(), v.end(), w.begin(), v.begin(), telop);
copy(v.begin(), v.end(), iout);
cout<<endl;
// Bewerking opgeven met standaard functie-objecten.
transform(v.begin(), v.end(), w.begin(), v.begin(), plus<int>());
copy(v.begin(), v.end(), iout);
cout<<endl;
// Bewerking opgeven met boost lambda functie-objecten.
![]()
transform(v.begin(), v.end(), w.begin(), v.begin(), [](int i1, int i2) {
return i1 + i2;
});
copy(v.begin(), v.end(), iout);
cout<<endl;
cin.get();
return 0;
}
remove_if
.
#include <iostream>
#include <vector>
#include <iterator>
#include <functional>
#include <algorithm>
using namespace std;
int main() {
vector<int> v;
for (int i(0); i<10; ++i) {
v.push_back(i*i);
}
ostream_iterator<int> out(cout, " ");
cout<<"Na initialisatie:"<<endl;
copy(v.begin(), v.end(), out);
auto end(remove_if(v.begin(), v.end(), [](int i) {
![]()
return !(i%2);
}));
cout<<endl<<"Na remove (tot returned iterator):"<<endl;
copy(v.begin(), end, out);
cout<<endl<<"Na remove (hele vector):"<<endl;
copy(v.begin(), v.end(), out);
v.erase(end, v.end());
cout<<endl<<"Na erase (hele vector):"<<endl;
copy(v.begin(), v.end(), out);
cin.get();
return 0;
}
for_each
met aanroep van een memberfunctie.
#include <iostream>
#include <list>
#include <algorithm>
#include <functional>
using namespace std;
class Hond {
public:
virtual ~Hond() {
}
virtual void blaf() const =0;
};
class Tekkel: public Hond {
public:
virtual void blaf() const {
cout<<"Kef kef ";
}
};
class StBernard: public Hond {
public:
virtual void blaf() const {
cout<<"Woef woef ";
}
};
int main() {
list<Hond*> kennel;
kennel.push_back(new Tekkel);
kennel.push_back(new StBernard);
kennel.push_back(new Tekkel);
// aanroepen van een memberfunctie via mem_fun
for_each(kennel.begin(), kennel.end(), mem_fun(&Hond::blaf));
cout<<endl;
// aanroepen van een memberfunctie via lambda functie
![]()
for_each(kennel.begin(), kennel.end(), [](Hond* h) {
h->blaf();
});
cout<<endl;
cin.get();
return 0;
}
#include <iostream>
#include <list>
#include <algorithm>
#include <string>
using namespace std;
class Hond {
private:
string n;
public:
virtual ~Hond() {
}
string naam() const {
return n;
}
void geefNaam(const string& s) {
n=s;
}
virtual string blaf() const =0;
};
class Tekkel: public Hond {
public:
virtual string blaf() const {
return "Kef kef ";
}
};
class StBernard: public Hond {
public:
virtual string blaf() const {
return "Woef woef ";
}
};
// handige template:
template<typename Container, typename Functor> void for_all(Container& c, Functor f) {
for_each(c.begin(), c.end(), f);
}
int main() {
list<Hond*> kennel;
kennel.push_back(new Tekkel);
kennel.push_back(new StBernard);
kennel.push_back(new Tekkel);
// blaffen zonder naam
for_all(kennel, [](Hond* h) {
cout<<h->blaf();
});
cout<<endl;
// alle honden heten "Fikkie"
![]()
for_all(kennel, [](Hond* h) {
h->geefNaam("Fikkie");
});
// blaffen met naam
for_all(kennel, [](Hond* h) {
cout<<h->naam()<<":"<<h->blaf();
});
cout<<endl;
cin.get();
return 0;
}
set
en for_each
.
#include <iostream>
#include <string>
#include <set>
#include <algorithm>
#include <iterator>
using namespace std;
int main() {
string w("galgje");
set<char> letters, geraden;
copy(w.begin(), w.end(), inserter(letters, letters.begin()));
do {
for_each(w.begin(), w.end(), [&](char c) {
if (geraden.count(c))
cout<<c;
else
cout<<'.';
});
cout<<endl<<"Raad een letter: ";
char c;
cin>>c;
geraden.insert(c);
}
while (!includes(geraden.begin(), geraden.end(), letters.begin(), letters.end()));
cout<<"Je hebt het woord "<<w<<" geraden."<<endl;
cin.get(); cin.get();
return 0;
}
De notatie [&]
geeft aan dat alle variabelen die niet in
de lambda functie gedefinieerd zijn maar wel in de lambda functie gebruikt
worden (in dit geval de set geraden
) als referentie aan de lambda
functie "gekoppeld" moeten worden. Een verzameling "gekoppelde" variabelen
wordt een closure genoemd.
De set geraden
kan nu gewoon lokaal in de functie
main
worden gedefinieerd. De lambda functie die in de
for_each
als derde parameter wordt ingevuld kan ook op een
alternatieve manier worden opgegeven:
for_each(w.begin(), w.end(), [&](char c) {
cout<<(geraden.count(c)?c:'.');
});
string
en
transform
.
#include <iostream>
#include <string>
#include <set>
#include <algorithm>
using namespace std;
int main() {
string w("galgje");
string geraden(w.length(), '.');
do {
cout<<geraden<<endl<<"Raad een letter: ";
char c;
cin>>c;
transform(w.begin(), w.end(), geraden.begin(), geraden.begin(), [=](char w_char, char geraden_char) {
return w_char==c?w_char:geraden_char;
});
}
while (geraden!=w);
cout<<"Je hebt het woord "<<w<<" geraden."<<endl;
cin.get(); cin.get();
return 0;
}
De notatie [=]
geeft aan dat alle variabelen die niet in de
lambda functie gedefinieerd zijn maar wel in de lambda functie gebruikt worden
(in dit geval het karakter c
) als waarde aan de lambda functie
"gekoppeld" moeten worden. Een verzameling "gekoppelde" waarden wordt een
closure genoemd.
In plaats van de operator ?:
kunnen we in de lambda functie
ook een if else
statement gebruiken. Omdat de lambda functie
dan uit meerdere statements bestaat moeten we het returntype opgeven door
middel van ->
char
.
#include <iostream>
#include <string>
#include <set>
#include <algorithm>
using namespace std;
int main() {
string w("galgje");
string geraden(w.length(), '.');
do {
cout<<geraden<<endl<<"Raad een letter: ";
char c;
cin>>c;
transform(w.begin(), w.end(), geraden.begin(), geraden.begin(), [=](char w_char, char geraden_char) -> char {
if (w_char==c)
return w_char;
else
return geraden_char;
});
}
while (geraden!=w);
cout<<"Je hebt het woord "<<w<<" geraden."<<endl;
cin.get(); cin.get();
return 0;
}
for_each
.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
int main() {
vector<int> v;
for (int i(1); i<11; ++i)
v.push_back(i);
ostream_iterator<int> iout(cout, " ");
copy(v.begin(), v.end(), iout);
cout<<endl;
int somEven = 0;
for_each(v.begin(), v.end(), [&somEven](int i) {
if (i%2 == 0)
somEven += i;
});
cout<<"Som van de even getallen is: "<<somEven<<endl;
cin.get();
return 0;
}
De notatie [&somEven]
geeft aan dat de variabele
somEven
die niet in de lambda functie gedefinieerd is maar wel
in de lambda functie gebruikt wordt als referentie aan de lambda functie
"gekoppeld" moeten worden. Als alternatief kan ook de notatie
[&]
gebruikt worden.