Consider you have a Person
class:
class Person { private: string firstName; string lastName; int id; public: Person(const string& fn, const string& ln, int i) : firstName(fn), lastName(ln), id(i) { } const string& getFirstName() const { return firstName; } const string& getLastName() const { return lastName; } int getID() const { return id; } };
You want to store several instances of this class in a vector:
vector people; people.push_back(Person("Davor", "Loayza", 62341)); people.push_back(Person("Eva", "Lopez", 12345)); people.push_back(Person("Julio", "Sanchez", 54321)); people.push_back(Person("Adan", "Ramones", 70000));
If you want to sort this vector by the person ID, you could implement a PersonComparator and use the STL sort algorithm:
class PersonComparator { public: bool operator()(const Person& p1, const Person& p2) const { return p1.getID() < p2.getID(); } }; PersonComparator pc; sort(people.begin(), people.end(), pc);
In C++03 you need to create a separate class (or alternatively a function) to use the sort algorithm (actually to use any STL algorithm). C++0x introduces the "lambda expressions", that are a nice way to implement the functionality passed to the algorithm when it is going to be used. So, instead of declaring the PersonComparator as shown above, you could implement the same functionality in this way:
sort(people.begin(), people.end(), [](const Person& p1, const Person& p2)
{
return p1.getID() < p2.getID();
});
Quite simple and easier to read. The "[]" angle brackets are used to mark the extern variables that will be used in the lambda context. "[]" means: "I do not want my lambda function to capture anything"; "[=]" means: "everything passed by value" (thanks Jeff for your clarification on this!!); "[&]" means: "everything passed by reference".
Given the vector declared above, what if you want to show all instances inside it, you could do this in C++03:
ostream& operator<<(ostream& os, const Person& p)
{
os << "(" << p.getID() << ") " << p.getLastName() << "; " << p.getFirstName();
return os;
}
class showall
{
public:
void operator()(const Person& p) const { cout << p <= min && id <= max)
cout << p << endl;
}
};
showrange sr(20000, 60000);
for_each(people.begin(), people.end(), sr);
And with lambdas you could do both examples in this way:
for_each(people.begin(), people.end(), [](const Person& p)
{
cout << p <= min && id <= max)
cout << p << endl;
});
i would love to be able to use auto inside of the lamda expression argument list … something like
but that *does not* work :(
is there a solution for me?
Using
auto
as part of the argument list is not allowed, so, your example wouldn’t work; but, what if you do something like this:multiplyByN(a, 5);
and implement it in this way:
It works perfectly!
thanks for the quick response :)
well the example i provided was just off the cuff but thanks anyways for providing an example …
actually the beauty for using lambdas, for me at least, was not writing functors or external functions like the one you kindly provided… i wanted to be able to write a lambda just where i needed it which invariably was within a function body. this way i kept all the related code pieces together. i guess the compiler implements lambdas as functors behind the scenes but at least my code looks pristine.
i was hoping that by using
auto
within lambda argument list i would move closer to generic programming.i was actually trying out a piece of code and i could not figure out whether an iterator was being passed to the unary function or an element so wanted to use
auto
to take the guesswork out.so, just out of curiosity, if you can’t use “auto” could you do:
std::for_each (a.begin(), a.end(), [](&decltype(expression_poster_is_evaluating) i) { i *= 5;});
instead?
Hi Rino, yeap, you can say something like:
for_each(v.begin(), v.end(), [](decltype(*(v.begin()) i) { i* = n; });
Hi! Your posts are very informative, but I noticed a small mistake midway through this article.
Empty brackets mean the lambda takes nothing (I forget the technical term for it), [=] means take everything by value, and [&] means take everything by default (like you said). You can also mix and match what you take by value and what you take by reference.
I’ve learned a lot from your posts: Thanks again!
-Jeff
Thanks for your nice comment Jeff and for your clarification. I already updated the post fixing the error. Thanks for reading me :)
Shouldn’t it be
return (p1.getID() – p2.getID()) < 0;
rather than just
return p1.getID() – p2.getID();
?
See
http://www.sgi.com/tech/stl/sort.html
http://www.sgi.com/tech/stl/StrictWeakOrdering.html
Ohh! sorry! yes, of course you are completely right! :) I’ll update that error right now!
Thanks for reading me! :)
Nice posts!
One question: in the last snippet, you added int id = getID();. Shouldn’t it be int id = p.getID(); ?
You are completely right. Fixed! :)