Σερφάροντας στο νετ έπεσα πάνω σε ένα άρθρο το οποίο έλεγε οτι έρχεται το νέο standar της c++ με όνομα "c++ 0x". Λεό από μέσα μου "εδώ είσαι". Μέτα από αρκετή ώρα, κόλλησε το μάτι μου στο lambda expression, απίστευτο! η c++ υποστηρίζει lambdas.
Λοιπόν τι είναι το lambda, είναι μια συνάρτηση χωρίς όνομα.
Η σύνταξη της είναι
[] { }
Το [] λέει στο compiler οτι ακολουθεί μια lambda.
Το {} είναι το σώμα της συνάρτησης.
Η δήλωση της μπορεί να γίνει με δυο τρόπους.
1) με χρήση του template function (header "functional")
function<void(void)> f = []{};
2) με το keyword auto.
auto f = [] { };
Ενα παράδειγμα χρήσης μιας lambda
#include <iostream>
#include <functional>using std::function;using std::cout;using std::cin;using std::endl;
void execute_lambda(function<void(void)> l){ l();}int main(int a,char** b) { execute_lambda([] { cout<<"hello from lambda!"<<endl; });
cin.get(); return 0;}
Θα μου πεις, "σίγα το πράμα που κάνει αυτό το μαραφέτι". Συμφωνώ! Αυτή είναι η απλούστερη σύνταξη, την έγραψα για να γίνει εύκολα κατανοητή.
Τι άλλο μας προσφέρει,
1 μπορεί να επιστρέψει μια μεταβλητή,
2 μπορεί να πάρει κάποια παράμετρο
Για να πάρουμε κάτι απο μια lambda πρέπει να υπάρχει μεσα στο σώμα της το keyword return
[]{ return 1;};
Παράδειγμα, μια Λ που επιστρέφει την λέξη hello
#include <iostream>
#include <functional>using std::function;using std::cout;using std::cin;using std::endl;
int main(int a,char** b) { auto f = []{ return "hello";}; cout<<f(); cin.get(); return 0;
}
Ο τύπος βγαίνει αυτόματα, εάν δεν είναι γνωστός ο τύπος μέσα στο body τότε βάζουμε το σύμβολο -> το οποίο θα αναλύσω πιο κάτω.
Και τώρα πάμε στο δύσκολου μέρος της Λ. Η Διαχείριση των παραμέτρων και μεταβλητών.
Για να εισάγουμε κάποια παράμετρο θα πρέπει να δούμε πως είναι η σύνταξή της Λ με παραμέτρους. Στην ουσία μπαίνει άλλο ενα σύμβολο, οι παρενθέσεις, η νέα μας Λ είναι ετσι [](){}; .
Μπορούμε να εισάγουμε παραμέτρους με δυο τρόπους.
1) by value [](int i){};
2) by ref [](int& i){};
2) by ref [](int& i){};
Με το by value δημιουργούμε ενα αντίγραφο της παραμέτρου, αρα ο,τι και να κάνουμε μέσα στη Λ δεν θα αλλάξει το i. Παράδειγμα μια Λ που επιστρέφει το τετράγωνο της μεταβλητής
#include <iostream>
#include <functional>
using std::function;
using std::cout;
using std::cin;
using std::endl;
int main(int a,char** b)
{
int i = 3;
auto f = [](int i)
{
return i*i;
};
cout<<f(i);
cin.get();
return 0;
}
Με το by ref περνούμε την διεύθυνση της παράμετρο, αρα η παράμετρος μπορεί να αλλάξει κατάσταση μέσου της Λ. Παράδειγμα μια Λ που αλλάζει την παράμετρο.
#include <iostream>
#include <functional>
using std::function;
using std::cout;
using std::cin;
using std::endl;
int main(int a,char** b)
{
int i = 3;
auto f = [](int& i)
{
i = 100000;
};
f(i);
cout<<i;
cin.get();
return 0;
}
Αυτά με τις παραμέτρους. Τώρα τι κάνουμε με τις μεταβλητές; Μια Λ είναι ένα πρότυπο το οποιο μπορεί να εκτελεστεί οπού να'ναι, με αποτέλεσμα να βλέπει μονό global vars. Δηλαδή στο παρακάτω παράδειγμα
#include <iostream>
#include <functional>using std::function;using std::cout;using std::cin;using std::endl;
void foo(function<void(void)> f){ f();}int main(int a,char** b) { int i = 3; foo([] { i = 100000; }); cin.get(); return 0;
}
Αυτό δεν γίνετε compile επειδή στη main έχουμε τη κατασκευή της Λ και η εκτέλεση της γίνετε στη foo, στη foo ωμός δεν υπάρχει κάποια μεταβλητή i αρα πάπαλα. Φυσικά υπάρχει τρόπος να περάσεις μεταβλητές στο scop μιας Λ και αυτο γίνεται με 4 τρόπους. Όλα by value, όλα by ref, επιλεγμένα by value επιλεγμένα by ref.
1) Όλα by value η Λ βλέπει όλο το scop στο οποίο βρίσκετε/κατασκευάζεται, οτι χρησιμοποιεί το έχει ως αντίγραφο και η σύνταξη της είναι η εξής
[=]{};
πχ
#include <iostream>#include <functional>using std::function;using std::cout;using std::cin;using std::endl;
void foo(function<void(void)> f){ f();}int main(int a,char** b) { int i = 3; foo([=] { cout<<i; }); cin.get(); return 0;
}
2) Όλα by ref η Λ βλέπει όλο το scop στο οποίο βρίσκετε/κατασκευάζεται, οτι χρησιμοποιεί μπορεί να το αλλάξει και η σύνταξη της είναι η εξής
[&]{};
πχ
#include <iostream>#include <functional>using std::function;using std::cout;using std::cin;using std::endl;
void foo(function<void(void)> f){ f();}int main(int a,char** b) { int i = 3; foo([&] { i=1000; }); cout<<i; cin.get(); return 0;
}
3) Επιλεγμένα by value, μπορείς να πεις ποιες μεταβλητές θέλεις η σύνταξη της είναι
[όνομα-μεταβλητής]{};
πχ
#include <iostream>
#include <functional>using std::function;using std::cout;using std::cin;using std::endl;
void foo(function<void(void)> f){ f();}int main(int a,char** b) { int i = 3; foo([i] { cout<<i; });
cin.get(); return 0;
}
4) Επιλεγμένα by ref, μπορείς να πεις ποιες μεταβλητές θέλεις η σύνταξη της είναι
[&όνομα-μεταβλητής]{};
πχ
#include <iostream>#include <functional>using std::function;using std::cout;using std::cin;using std::endl;
void foo(function<void(void)> f){ f();}int main(int a,char** b) { int i = 3; foo([&i] { i = 1000; }); cout<<i; cin.get(); return 0;
}
Επίσης μπορείς να κάνεις και συνδυασμούς
[&i,y,x,&z]{};
Αυτά και με τους παραμέτρους και μεταβλητές.
Τελευταία δυνατότητα της Λ είναι ο καθορισμός του τύπου επιστροφής. Και η πλήρη σύνταξη της είναι η εξής
[scope_define](args_define)->type_define{body_define}
πχ
#include <iostream>#include <functional>using std::function;using std::cout;using std::cin;using std::endl;
class base{};class drived:public base{};int main(int a,char** b) { auto f = []()->base* { return new drived(); }; base *b = f(); cin.get(); return 0;
}
Τέλος μια υλοποίηση τύπου where και χρήση lambdas
#include <iostream>
#include <functional>#include <vector>#include <string>using std::function;using std::cout;using std::cin;using std::endl;using std::vector;using std::string;struct Person{ string Name; int Age; Person(string name,int age) { Name = name; Age = age; }};template<class T>vector<T> where_(vector<T> p,function<bool(T)> f){ vector<T> v; auto inF = p.begin(),inL = p.end(); for(;inF!=inL;++inF) if(f(*inF)) v.push_back(*inF); return v;}int main(int a,char** b) { vector<Person> p; p.push_back( Person("Alex",20)); p.push_back( Person("Manos",33)); p.push_back( Person("Elen",18)); p.push_back( Person("Maria",20)); p.push_back( Person("Mitsos",20));
vector<Person> only20age = where_<Person>(p,[](Person p)->bool { if(p.Age == 20) return true; else return false; }); for(unsigned i =0 ; i < only20age.size();i++) cout<<only20age[i].Name<<endl; cin.get(); return 0;
}
Δεν είναι απίστευτο;
Γραψτε και κανα σχολια καλοι μου ανθρωποι! Αρνητικο θετικο οτι να'ναι δεν εχω προβλημα.
ΑπάντησηΔιαγραφήΠολυ καλος!
ΑπάντησηΔιαγραφήΤα lambda είναι τρομερά. Τα έχω χρησιμοποιήσει πολύ στην C# (έχουν διαφορετική σύνταξη εκεί βεβαια) όπου πραγματικά αν τα συνηθίσεις μετά δε κανεις βήμα χωρίς αυτά.