C++: Lambda expressions

Having this Person class:

class Person
{
  private:
    std::string firstName;
    std::string lastName;
    int id;

  public:
    Person(const std::string& fn, const std::string& ln, int i)
    : firstName{fn}
    , lastName{ln}
    , id{i}
    {
    }

    const std::string& getFirstName() const { return firstName; }
    const std::string& getLastName() const { return lastName; }
    int getID() const { return id; }
};

The programmers need to store several instances of this class in a vector:

std::vector<Person> 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 they want to sort this vector by person ID, a PersonComparator must be implemented to be used in the std::sort algorithm from the standard library:

class PersonComparator
{
  public:
     bool operator()(const Person& p1, const Person& p2) const
     {
        return p1.getID() < p2.getID();
     }
};

PersonComparator pc;
std::sort(people.begin(), people.end(), pc);

Before C++11, the programmers needed to create a separate class (or alternatively a function) to use the sort algorithm (actually to use any standard library algorithm).

C++11 introduced “lambda expressions”, which are a nice way to implement that functionality to be passed to the algorithm exactly when it is going to be used. So, instead of defining the PersonComparator as shown above, the same functionality could be achieved by implementing it in this way:

std::sort(people.begin(), people.end(), [](const Person& p1, const Person& p2)
{
  return p1.getID() < p2.getID();
});

Quite simple and easier to read. The “[]” square brackets are used to mark the external 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 the programmers want to show all instances inside it? They could do this before C++11:

std::ostream& operator<<(std::ostream& os, const Person& p)
{
    os << "(" << p.getID() << ") " << p.getLastName() << "; " << p.getFirstName();
    return os;
}

class show_all
{
public:
    void operator()(const Person& p) const
    { 
        std::cout << p << std::endl;
    }
};

show_all sa;
std::for_each(people.begin(), people.end(), sa);

And with lambdas the example could be implemented in this way:

std::for_each(people.begin(), people.end(), [](const Person& p)
{
    std::cout << p << std::endl;
});