2

For lambda expressions, I don't quite get the usefulness of closures in C++11.

auto f = [] (int n, int m) { return n + m };
std::cout << f(2,2);

versus.

int n = 2;
auto f = [n] (int m) { return n + m };
std::cout << f(2);

This is a very basic and primitive example. I'm guessing that closures play an important part in other kinds of statements, but my C++ book doesn't clarify this (so far).

Why not include the closure as a parameter?

3
  • 8
    Because sometimes you need something that only has one parameter. Commented Jul 4, 2014 at 16:10
  • @juanchopanza A simple example would be nice mate. Commented Jul 4, 2014 at 16:23
  • @user3407764 Standard library algorithms, for instance, all expect something that takes a certain number of parameters (the exact number depends on the algorithm: std::generate expects something that takes no parameter; std::find_if expects something that takes one, etc.). Commented Jul 4, 2014 at 16:28

2 Answers 2

3

OK, a simple example, remove all the x's from a string

char x = 'x';
std::string s = "Text to remove all 'x's from";
s.erase(std::remove_if(s.begin(), s.end(), [x](char c) {return x == c;}), s.end());

Borrowed and modifed from http://en.cppreference.com/w/cpp/algorithm/remove

In this example, remove_if() only takes a single parameter, but I need two values for the comparison.

Sign up to request clarification or add additional context in comments.

Comments

0

Closures are not always called immediately. They are objects which can be stored and called later when the data necessary to successfully execute the lambda function may no longer be in scope or easily accessible from the call site.

It's possible to to store any necessary data along with the closure but it's so much simpler for the closure to grab anything it needs when it's created and use it when it's eventually called. It provides a form of encapsulation.

This also decreases code coupling because if you were to store the data along with the code then the caller could only work with the specific objects you decided to store. Since a closure carries its own data along with it, it can work with any data it needs.

Here's an greatly oversimplified real-life example. I built a database server which needed to support fields with multiple values. The problem was that when results were displayed, it was important to highlight which values actually caused a record to match the search criteria. So, the query parser would spit out a predicate in the form of a closure which would indicate whether or not it was a matching value.

It looked something like this:

std::function< bool(int value) > parser::match_int(int search_val) {
    return [=](int value) { value == search_val; };
}

That closure got stored in a collection. When it was time to render the record, I could easily determine which values needed to be highlighted. Keep in mind that the parser and any associated data is now gone:

void render_values(std::function< bool(int value) > pred, std::vector<int> values) {
    for (int value : values) {
        if (pred(value))
            render_highlight(value);
        else
            render_normal(value);
    }
}

1 Comment

I had to use a little bit of time understanding the code and what you wanted to do with it, but once I got it this answer was really great. Very nice, thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.